﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Markup;

namespace Geometry
{
    public sealed class LineXLinePoint : GObjectBase, IGPoint
    {
        public LineXLinePoint()
        {
            UpdateBoundingBox();
        }

        public LineXLinePoint(IGLine _line1, IGLine _line2)
        {
            this.Line1 = _line1;
            this.Line2 = _line2;
            UpdatePosition();
            UpdateBoundingBox();
        }

        protected override void ReleaseDependencies()
        {
            this.Line1 = null;
            this.Line2 = null;
        }

        protected override void UpdateBoundingBox()
        {
            base.BoundingBox = new Rect(Position, Position);
        }

        private IGLine m_Line1;
        public IGLine Line1
        {
            get
            {
                return m_Line1;
            }
            set
            {
                if (m_Line1 == value) return;

                if (m_Line1 != null) m_Line1.PropertyChanged -= new PropertyChangedEventHandler(_related_PropertyChanged);
                m_Line1 = value;
                if (m_Line1 != null) m_Line1.PropertyChanged += new PropertyChangedEventHandler(_related_PropertyChanged);

                RaisePropertyChanged("Line1");
                UpdatePosition();
            }
        }

        private IGLine m_Line2;
        public IGLine Line2
        {
            get
            {
                return m_Line2;
            }
            set
            {
                if (m_Line2 == value) return;

                if (m_Line2 != null) m_Line2.PropertyChanged -= new PropertyChangedEventHandler(_related_PropertyChanged);
                m_Line2 = value;
                if (m_Line2 != null) m_Line2.PropertyChanged += new PropertyChangedEventHandler(_related_PropertyChanged);

                RaisePropertyChanged("Line2");
                UpdatePosition();
            }
        }

        void _related_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName != "Slope") return;

            UpdatePosition();
        }

        private void UpdatePosition()
        {
            if (m_Line1.IsNull() || m_Line2.IsNull()) return;

            double d = ((m_Line2.Point2.Y - m_Line2.Point1.Y) * (m_Line1.Point2.X - m_Line1.Point1.X)) -
              ((m_Line2.Point2.X - m_Line2.Point1.X) * (m_Line1.Point2.Y - m_Line1.Point1.Y));

            double m = ((m_Line2.Point2.X - m_Line2.Point1.X) * (m_Line1.Point1.Y - m_Line2.Point1.Y)) -
                           ((m_Line2.Point2.Y - m_Line2.Point1.Y) * (m_Line1.Point1.X - m_Line2.Point1.X));

            double n = ((m_Line1.Point2.X - m_Line1.Point1.X) * (m_Line1.Point1.Y - m_Line2.Point1.Y)) -
                           ((m_Line1.Point2.Y - m_Line1.Point1.Y) * (m_Line1.Point1.X - m_Line2.Point1.X));

            if (0 == d)
            {
                if (0 == m && 0 == n)
                {
                    return; // same line
                }
                return; // parallel
            }

            this.Position = m_Line1.Point1 + (m_Line1.Point2 - m_Line1.Point1) * (m / d);
        }

        #region IGPoint Members
        private Point m_Position;

        public double PosX
        {
            get { return m_Position.X; }
            private set
            {
                if (value.Equals(m_Position.X)) return;
                m_Position.X = value;
                UpdateBoundingBox();
                RaisePropertyChanged("PosX");
                RaisePropertyChanged("Position");
            }
        }

        public double PosY
        {
            get { return m_Position.Y; }
            private set
            {
                if (value.Equals(m_Position.Y)) return;
                m_Position.Y = value;
                UpdateBoundingBox();
                RaisePropertyChanged("PosY");
                RaisePropertyChanged("Position");
            }
        }

        public Point Position
        {
            get { return m_Position; }
            private set
            {
                if (value.Equals(m_Position)) return;
                m_Position = value;
                UpdateBoundingBox();
                RaisePropertyChanged("Position");
                RaisePropertyChanged("PosX");
                RaisePropertyChanged("PosY");
            }
        }

        #endregion
    }
}
